home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
graphics
/
beztwist.arc
/
BEZTWIST.C
next >
Wrap
C/C++ Source or Header
|
1986-02-06
|
8KB
|
364 lines
/* beztwist.c 17-Sep-88
**
** Display some twisting cubic Bezier curves.
** Shows speed of code generated by the Turbo C compiler.
** Works with all 3 resolution modes of the Atari ST.
*/
#include <tos.h>
#include <stdlib.h>
#include "grtypes.h"
#define NULL ((void *) 0L)
#define NIL ((void *) -1L)
typedef struct {
SCREEN screen;
RESOLUTION res;
int planes, words_per_line;
COLOR color, col_mask;
COORD x_max, y_max;
long max_area;
} INFO;
typedef struct {
COORD x[4];
COORD y[4];
int active;
} BEZIER;
#define N 10 /* length of FIFO queue */
#define FLAT 32
#define CONSOLE 2
#define BITS 5
#define SCALE (1 << BITS)
#define SCALE_2 (1 << (BITS-1))
/* draw_line()
**
** Draw a line from point (x_from, y_from) to point (x_to, y_to).
** Use Bresenham's line drawing algorithm with incremental
** screen address computation and inline plotting. (Fast!)
*/
void
draw_line( register INFO *info,
COORD x_from, COORD y_from,
COORD x_to, COORD y_to)
{
register SCREEN screen;
COORD delta_x, delta_y, incr_left, incr_left_up;
COORD count, dist, offset;
register COLOR color;
register WORD or_mask, and_mask;
int flag;
delta_y = y_to - y_from;
if ((delta_x = x_to - x_from) < 0) {
delta_x = -delta_x;
delta_y = -delta_y;
x_from = x_to;
y_from = y_to;
}
if (delta_y < 0) {
offset = -info->words_per_line;
delta_y = -delta_y;
} else {
offset = info->words_per_line;
}
if (delta_x < delta_y) {
flag = 1;
count = delta_y;
delta_y = delta_x;
delta_x = count;
} else {
flag = 0;
count = delta_x;
}
screen = info->screen +
((y_from * info->words_per_line) +
(x_from >> 4) * info->planes);
or_mask = 0x8000 >> (x_from & 0x0f);
incr_left = 2 * delta_y;
dist = incr_left - delta_x;
incr_left_up = dist - delta_x;
color = info->color;
for (;;) {
and_mask = ~or_mask;
switch (info->res) {
case low_res:
if (color & 8) screen[3] |= or_mask;
else screen[3] &= and_mask;
if (color & 4) screen[2] |= or_mask;
else screen[2] &= and_mask;
case med_res:
if (color & 2) screen[1] |= or_mask;
else screen[1] &= and_mask;
case hi_res:
if (color & 1) screen[0] |= or_mask;
else screen[0] &= and_mask;
default:
break;
}
if (count == 0) break;
count--;
if (dist >= 0) {
/* Move 1 pixel 'left' and 'up'. */
dist += incr_left_up;
or_mask >>= 1;
screen += offset;
} else {
/* Move 1 pixel 'left'. */
dist += incr_left;
if (flag)
screen += offset;
else
or_mask >>= 1;
}
if (or_mask == 0x0000) {
screen += info->planes;
or_mask = 0x8000;
}
}
}
/* bezier()
**
** Draw the cubic Bezier curve specified by P0, P1, P2 and P3
** by subdividing it recursively into sub-curves until it
** can be approximated smoothly by straight line segments.
** We use fixed point arithmetic to achieve increased precision
** in coordinate computations. The control points have been
** scaled with SCALE and 0.5 has been added to the coordinates
** so that we can feed rounded coordinate values to draw_line().
*/
void
bezier( INFO *info,
long x0, long y0, long x1, long y1,
long x2, long y2, long x3, long y3)
{
long v1x, v1y, v2x, v2y, v3x, v3y;
long vcp1, vcp2, vcp3, area;
long mid_x, mid_y;
int code;
/*
** Stop the recursion when the size of the area covered
** by the convex hull of the Bezier curve is less than or
** equal to info->max_area.
*/
/* First, compute direction vectors. */
v3x = x3 - x0; v3y = y3 - y0;
v2x = x2 - x0; v2y = y2 - y0;
v1x = x1 - x0; v1y = y1 - y0;
/* Then, compute vector cross products. */
code = 0;
if ((vcp1 = v3x * v2y - v2x * v3y) < 0) code += 4;
if ((vcp2 = v3x * v1y - v1x * v3y) < 0) code += 2;
if ((vcp3 = v2x * v1y - v1x * v2y) < 0) code += 1;
/* Finally, compute size of area covered by convex hull. */
/* We actually compute 2*area, but that doesn't matter much. */
switch (code) {
case 0:
case 2:
case 5:
case 7: area = vcp1 + vcp3; break;
case 1:
case 6: area = vcp2 - vcp3; break;
case 3:
case 4: area = vcp1 - vcp2; break;
default: return;
}
if (code & 4) area = -area;
if (area <= info->max_area) {
/* Stop recursion and draw a line from P0 to P3. */
/* Rescale and round coordinates before */
/* feeding them to draw_line(). */
draw_line(info,
x0 >> BITS, y0 >> BITS, x3 >> BITS, y3 >> BITS);
} else {
/* Area is still too big, so subdivide the curve into */
/* two sub-curves and draw these recursively. */
mid_x = (x0 + 3*x1 + 3*x2 + x3) >> 3;
mid_y = (y0 + 3*y1 + 3*y2 + y3) >> 3;
bezier( info,
x0, y0,
(x0 + x1) >> 1, (y0 + y1) >> 1,
(x0 + 2*x1 + x2) >> 2, (y0 + 2*y1 + y2) >> 2,
mid_x, mid_y);
bezier( info,
mid_x, mid_y,
(x1 + 2*x2 + x3) >> 2, (y1 + 2*y2 + y3) >> 2,
(x2 + x3) >> 1, (y2 + y3) >> 1,
x3, y3);
}
}
/*
** Show some randomly twisting bezier curves.
*/
int
main(argc, argv)
int argc;
char *argv[];
{
INFO info;
BEZIER list[N];
BEZIER *q;
COORD dx[4], dy[4];
COORD *p;
COLOR color;
int i, j, k, n;
long loop = -1, flat = 0;
if (argc >= 2)
loop = atoi(argv[1]);
if (loop < 1)
loop = -1;
if (argc >= 3)
flat = atoi(argv[2]);
info.screen = Physbase();
Setscreen(NIL, NIL, info.res = Getrez());
switch (info.res) {
case hi_res:
info.x_max = HI_X_MAX;
info.y_max = HI_Y_MAX;
info.planes = HI_PLANES;
info.words_per_line = HI_WORDS_PER_LINE;
info.max_area = (flat >= 1 ? flat : FLAT) * SCALE * SCALE;
info.col_mask = HI_COLORS - 1;
color = HI_COLORS - 1;
break;
case med_res:
info.x_max = MED_X_MAX;
info.y_max = MED_Y_MAX;
info.planes = MED_PLANES;
info.words_per_line = MED_WORDS_PER_LINE;
info.max_area = (flat >= 1 ? flat : (3*FLAT)/4) * SCALE * SCALE;
info.col_mask = MED_COLORS - 1;
color = MED_COLORS - 1;
break;
case low_res:
info.x_max = LOW_X_MAX;
info.y_max = LOW_Y_MAX;
info.planes = LOW_PLANES;
info.words_per_line = LOW_WORDS_PER_LINE;
info.max_area = (flat >= 1 ? flat : FLAT/2) * SCALE * SCALE;
info.col_mask = LOW_COLORS - 1;
color = LOW_COLORS - 1;
break;
default:
return -1;
}
for (i = 1; i < N; i++)
list[i].active = 0;
i = 0;
q = &(list[0]);
q->active = 1;
for (k = 0; k < 4; k++) {
q->x[k] = Random() % (info.x_max + 1);
q->y[k] = Random() % (info.y_max + 1);
n = (Random() & 15) - 7;
if (n == 0) n = 1;
else if (n == 8) n = -1;
dx[k] = n;
n = (Random() & 15) - 7;
if (n == 0) n = 1;
else if (n == 8) n = -1;
dy[k] = n;
}
while (loop--) {
info.color = color;
bezier( &info,
q->x[0] * SCALE + SCALE_2, q->y[0] * SCALE + SCALE_2,
q->x[1] * SCALE + SCALE_2, q->y[1] * SCALE + SCALE_2,
q->x[2] * SCALE + SCALE_2, q->y[2] * SCALE + SCALE_2,
q->x[3] * SCALE + SCALE_2, q->y[3] * SCALE + SCALE_2);
j = i;
i = (i + 1) % N;
q = &(list[i]);
if (q->active) {
info.color = 0;
bezier( &info,
q->x[0] * SCALE + SCALE_2, q->y[0] * SCALE + SCALE_2,
q->x[1] * SCALE + SCALE_2, q->y[1] * SCALE + SCALE_2,
q->x[2] * SCALE + SCALE_2, q->y[2] * SCALE + SCALE_2,
q->x[3] * SCALE + SCALE_2, q->y[3] * SCALE + SCALE_2);
}
q->active = 1;
for (k = 0; k < 4; k++) {
p = &(q->x[k]);
*p = list[j].x[k] + dx[k];
if (*p < 0) {
*p += 8;
dx[k] = -dx[k];
} else if (*p > info.x_max) {
*p -= 8;
dx[k] = -dx[k];
}
p = &(q->y[k]);
*p = list[j].y[k] + dy[k];
if (*p < 0) {
*p += 8;
dy[k] = -dy[k];
} else if (*p > info.y_max) {
*p -= 8;
dy[k] = -dy[k];
}
}
if ((loop & 0xff) == 0) {
/* change direction */
k = Random() & 3;
n = (Random() & 15) - 7;
if (n == 0)